home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
src
/
demos
/
GL
/
flight
/
aifflib.c
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
22KB
|
1,084 lines
/*
* Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
* the contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
* and Computer Software clause at DFARS 252.227-7013, and/or in similar or
* successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
* rights reserved under the Copyright Laws of the United States.
*/
/*
* aifflib.c $Revision: 1.3 $
*
* A library for reading and writing AIFF files
*
* Chris Schoeneman - 1991
* (borrowed heavily from playaiff and recordaiff)
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#include <audio.h>
#include "aifflib.h"
/*
* AIFF file typedef's and defines
*/
typedef struct
{
long samprate;
long nchannels;
long sampwidth;
} audio_params_t;
typedef struct
{
char id[4];
long size;
} chunk_header_t;
#define CHUNK_ID 4
#define CHUNK_HEADER 8
typedef struct
{
chunk_header_t header;
int file_position; /* not in AIFF file */
char type[4]; /* should contain 'AIFF' for any audio IFF file */
} form_chunk_t;
#define FORM_CHUNK 12 /* including the header */
#define FORM_CHUNK_DATA 4
#define COMM_CHUNK 26 /* including the header */
#define COMM_CHUNK_DATA 18
typedef struct
{
chunk_header_t header;
int file_position; /* not in AIFF file */
short nchannels;
unsigned long nsampframes;
short sampwidth;
long samprate; /* not in AIFF file */
} comm_chunk_t;
#define SSND_CHUNK 16 /* including the header */
#define SSND_CHUNK_DATA 8
typedef struct
{
chunk_header_t header;
unsigned long offset;
unsigned long blocksize;
long file_position; /* not in AIFF file */
long sample_bytes; /* not in AIFF file */
} ssnd_chunk_t;
/*
* end of AIFF typedef's and defines
*/
#define MAXFILES 20
enum { FORM = 0, COMM = 1, SSND = 2};
#define DEFAULT_CHANNELS 2
#define DEFAULT_WIDTH 16
#define DEFAULT_RATE 48000
static int busy[MAXFILES],
ssnd_remaining[MAXFILES],
files = -1;
static long writepos[MAXFILES][3];
static FILE* aifffd[MAXFILES];
static audio_params_t audioparams[MAXFILES];
int AIFFerrno;
static char *AIFFerrstr[]={
"",
"too many open files",
"cannot open file",
"invalid file id",
"invalid data size",
"invalid header",
"not an AIFF file",
"no FORM header",
"invalid chunk",
"write failure",
"audio parameters are fixed",
"unsupported number of channels",
"unsupported sample width",
"unsupported sample rate"};
static int widthtobytes(int width);
static double ConvertFromIeeeExtended(char*);
static void ConvertToIeeeExtended(double, char*);
/*************************************************************************
** routines to read and write the AIFF format chunks **
*************************************************************************/
/*
* convert bytes in big endian order to a short
*/
static short align_short(char* buf)
{
int i;
union { unsigned char b[sizeof(short)]; short s; } align_short;
for (i = 0; i < sizeof(short); i++)
align_short.b[i] = *buf++;
return align_short.s;
}
/*
* convert bytes in big endian order to a long
*/
static long align_long(char* buf)
{
int i;
union { unsigned char b[sizeof(long)]; long l; } align_long;
for (i = 0; i < sizeof(long); i++)
align_long.b[i] = *buf++;
return align_long.l;
}
/*
* convert short to bytes in big endian order
*/
static void short_align(char* buf, short s)
{
int i;
char *scan = (char*)&s;
for (i = 0; i < sizeof(short); i++)
*buf++ = *scan++;
}
/*
* convert long to bytes in big endian order
*/
static void long_align(char* buf, long l)
{
int i;
char *scan = (char*)&l;
for (i = 0; i < sizeof(long); i++)
*buf++ = *scan++;
}
static int skip_chunk(AIFFfile fd, chunk_header_t* chunk_header)
{
fseek(aifffd[fd], chunk_header->size, SEEK_CUR);
}
static int read_chunk_header(AIFFfile fd, chunk_header_t *chunk_header)
{
char buf[CHUNK_HEADER];
int i;
if ((i = fread(buf, 1, CHUNK_HEADER, aifffd[fd])) != CHUNK_HEADER)
return i;
for (i=0; i<4; i++)
chunk_header->id[i] = buf[i];
chunk_header->size = align_long(buf+4);
return CHUNK_HEADER;
}
static int read_form_chunk(AIFFfile fd, chunk_header_t *chunk_header,
form_chunk_t *form_data)
{
char buf[FORM_CHUNK_DATA];
if (chunk_header->size < 0)
{
AIFFerrno = AIFF_BADDATASIZE;
return -1;
}
else if (chunk_header->size == 0)
{
AIFFerrno = AIFF_BADDATASIZE;
return -1;
}
if (fread(buf, 1, FORM_CHUNK_DATA, aifffd[fd]) != FORM_CHUNK_DATA)
{
AIFFerrno = AIFF_BADHEADER;
return -1;
}
if (strncmp(buf, "AIFF", 4))
{
AIFFerrno = AIFF_NOTAIFF;
return -1;
}
return 0;
}
static int read_comm_chunk(AIFFfile fd, chunk_header_t *chunk_header)
{
int i;
char buf[COMM_CHUNK_DATA+1];
comm_chunk_t comm_data;
if (fread(buf, 1, COMM_CHUNK_DATA, aifffd[fd]) != COMM_CHUNK_DATA)
{
AIFFerrno = AIFF_BADCHUNK;
return -1;
}
comm_data.nchannels = align_short(buf);
comm_data.nsampframes = align_long(buf+4);
comm_data.sampwidth = align_short(buf+6);
/*
* the sample rate value from the common chunk is an 80-bit IEEE extended
* floating point number:
* [s bit] [15 exp bits (bias=16383)] [64 mant bits (leading 1 not hidden)]
*
* turns out we can just grab bytes 2 and 3 (if bytes numbered 0 ... 9)
* and cast them as an integer: the integer value equals the sample rate
*/
comm_data.samprate = (long)ConvertFromIeeeExtended(buf+8);
audioparams[fd].samprate = comm_data.samprate;
audioparams[fd].nchannels = comm_data.nchannels;
audioparams[fd].sampwidth = comm_data.sampwidth;
if (widthtobytes(audioparams[fd].sampwidth) == -1)
{
AIFFerrno = AIFF_BADWIDTH;
audioparams[fd].sampwidth = DEFAULT_WIDTH;
return -1;
}
return 0;
}
/*
* AIFFread calls this if there is no more sound data in the current
* SSND chunk. It searches for the next block and sets the
* ssnd_remaining entry to the length of the block
*/
static void read_ssnd_chunk(AIFFfile fd)
{
char buf[SSND_CHUNK_DATA];
int i;
chunk_header_t chunk_header;
/*
* if no sound left, search for next SSND block
*
* NOTE: all chunks have been read through and checked for
* validity, so we assume read_chunk_header either returns
* zero for end of file or CHUNK_HEADER for a good block
*/
while (read_chunk_header(fd, &chunk_header) != 0)
{
if (!strncmp(chunk_header.id, "SSND", 4))
{
fread(buf, 1, SSND_CHUNK_DATA, aifffd[fd]);
ssnd_remaining[fd] = chunk_header.size - 2*sizeof(long);
if (ssnd_remaining[fd] != 0)
break;
}
else
skip_chunk(fd, &chunk_header);
}
}
static int write_form_chunk(AIFFfile fd)
{
char buf[FORM_CHUNK];
int i;
strncpy(buf, "FORM", 4); /* form header id */
for (i=0; i<sizeof(long); i++) /* form header size - do later */
buf[i+4] = 0x00;
strncpy(buf+4+sizeof(long), "AIFF", 4);
writepos[fd][FORM] = ftell(aifffd[fd]);
if (fwrite(buf, 1, FORM_CHUNK, aifffd[fd]) != FORM_CHUNK)
{
AIFFerrno = AIFF_WRITEFAILURE;
return -1;
}
return 0;
}
static int write_comm_chunk(AIFFfile fd)
{
char buf[COMM_CHUNK];
int i;
strncpy(buf, "COMM", 4); /* chunk id */
long_align(buf+4,COMM_CHUNK_DATA); /* chunk data size */
short_align(buf+4+sizeof(long), /* number channels */
audioparams[fd].nchannels);
long_align(buf+4+sizeof(long)+sizeof(short), /* nsample frames */
0L);
short_align(buf+4+2*sizeof(long)+sizeof(short), /* sample width */
audioparams[fd].sampwidth);
ConvertToIeeeExtended((double)audioparams[fd].samprate, /* sample rate */
buf + 4 + 2*sizeof(long) + 2*sizeof(short));
writepos[fd][COMM] = ftell(aifffd[fd]);
if (fwrite(buf, 1, COMM_CHUNK, aifffd[fd]) != COMM_CHUNK)
{
AIFFerrno = AIFF_WRITEFAILURE;
return -1;
}
ssnd_remaining[fd] = 0;
return 0;
}
static int write_ssnd_chunk(AIFFfile fd)
{
char buf[SSND_CHUNK];
int i;
strncpy(buf, "SSND", 4);
for (i=0; i<3*sizeof(long); i++) /* chunk data size */
buf[i+4] = 0x00;
writepos[fd][SSND] = ftell(aifffd[fd]);
if (fwrite(buf, 1, SSND_CHUNK, aifffd[fd]) != SSND_CHUNK)
{
AIFFerrno = AIFF_WRITEFAILURE;
return -1;
}
return 0;
}
static int update_form_chunk(AIFFfile fd, long total_bytes)
{
fseek(aifffd[fd], writepos[fd][FORM]+4, SEEK_SET);
total_bytes -= CHUNK_HEADER;
if (fwrite(&total_bytes, 1, sizeof(long), aifffd[fd]) != sizeof(long))
{
AIFFerrno = AIFF_WRITEFAILURE;
return -1;
}
return 0;
}
static int update_comm_chunk(AIFFfile fd, long sample_frames)
{
fseek(aifffd[fd], writepos[fd][COMM]+CHUNK_HEADER+sizeof(short), SEEK_SET);
if (fwrite(&sample_frames, 1, sizeof(long), aifffd[fd]) != sizeof(long))
{
AIFFerrno = AIFF_WRITEFAILURE;
return -1;
}
return 0;
}
static int update_ssnd_chunk(AIFFfile fd, long sample_bytes)
{
fseek(aifffd[fd], writepos[fd][SSND] + CHUNK_ID, SEEK_SET);
sample_bytes += SSND_CHUNK_DATA;
if (fwrite(&sample_bytes, 1, sizeof(long), aifffd[fd]) != sizeof(long))
{
AIFFerrno = AIFF_WRITEFAILURE;
return -1;
}
return 0;
}
static AIFFfile myopen(const char* filename, const char* dir)
{
int i;
FILE* fd;
/*
* find first available space in table
*/
for (i = 0; i < MAXFILES; i++)
if (!busy[i])
break;
if (i == MAXFILES)
{
AIFFerrno = AIFF_NOMEM;
return -1;
}
/*
* open file
*/
fd = fopen(filename, dir);
if (!fd)
{
AIFFerrno = AIFF_OPENFAILURE;
return -1;
}
/*
* fill table entries
*/
aifffd[i] = fd;
busy[i] = *dir;
files++;
return (AIFFfile)i;
}
static int myclose(AIFFfile fd)
{
busy[fd] = 0;
files--;
return fclose(aifffd[fd]);
}
AIFFfile AIFFopen(const char* filename, const char* dir)
{
AIFFfile fd;
int n;
chunk_header_t chunk_header;
form_chunk_t form_data;
fd = myopen(filename, dir);
if (fd < 0)
return fd;
switch (dir[0])
{
case 'r':
{
chunk_header_t chunk_header;
form_chunk_t form_data;
long past_header;
if (read_chunk_header(fd, &chunk_header) != CHUNK_HEADER)
{
myclose(fd);
AIFFerrno = AIFF_BADHEADER;
return -1;
}
if (strncmp(chunk_header.id, "FORM", 4)) /* form container */
{
AIFFerrno = AIFF_NOFORMCHUNK;
myclose(fd);
return -1;
}
if (read_form_chunk(fd, &chunk_header, &form_data) < 0)
{
myclose(fd);
return -1;
}
/*
* remember where interesting stuff starts
*/
past_header = ftell(aifffd[fd]);
/*
* search for last COMM chunk
*/
while ((n = read_chunk_header(fd, &chunk_header)) != 0)
{
if (n == CHUNK_HEADER)
{
if (!strncmp(chunk_header.id, "COMM", 4))
read_comm_chunk(fd, &chunk_header);
else
skip_chunk(fd, &chunk_header);
}
else
{
myclose(fd);
AIFFerrno = AIFF_BADHEADER;
return -1;
}
}
/*
* set file pointer to beginning of interesting stuff
*/
fseek(aifffd[fd], past_header, SEEK_SET);
ssnd_remaining[fd] = 0;
break;
}
case 'w':
{
/*
* write the form chunk
*/
if (write_form_chunk(fd) < 0)
{
myclose(fd);
return -1;
}
/*
* set ssnd_remaining to a bogus value as a flag to write the COMM
*/
ssnd_remaining[fd] = -1;
/*
* set default values for audio parameters
*/
AIFFsetchannels(fd,0);
AIFFsetwidth(fd,0);
AIFFsetrate(fd,0);
break;
}
}
return fd;
}
int AIFFclose(AIFFfile fd)
{
if (fd < 0 || fd >= MAXFILES || !busy[fd])
{
AIFFerrno = AIFF_BADFD;
return -1;
}
if (busy[fd] == 'w')
{
long total = ftell(aifffd[fd]);
if (update_form_chunk(fd, total) < 0)
{
myclose(fd);
return -1;
}
total -= FORM_CHUNK + COMM_CHUNK + SSND_CHUNK;
if (update_comm_chunk(fd, total / AIFFgetchannels(fd) /
widthtobytes(AIFFgetwidth(fd))) < 0)
{
myclose(fd);
return -1;
}
if (update_ssnd_chunk(fd, total) < 0)
{
myclose(fd);
return -1;
}
}
return myclose(fd);
}
int AIFFwrite(AIFFfile fd, const void* buf, unsigned nsamp)
{
int bytes_written;
unsigned nbyte;
if (fd < 0 || fd >= MAXFILES || !busy[fd])
{
AIFFerrno = AIFF_BADFD;
return -1;
}
/*
* write COMM and SSND block headers if necessary
*/
if (ssnd_remaining[fd] == -1)
{
if (write_comm_chunk(fd) < 0)
{
AIFFerrno = AIFF_WRITEFAILURE;
return -1;
}
if (write_ssnd_chunk(fd) < 0)
{
AIFFerrno = AIFF_WRITEFAILURE;
return -1;
}
}
/*
* convert number of samples to number of bytes
*/
nbyte = nsamp * widthtobytes(audioparams[fd].sampwidth);
bytes_written = fwrite(buf, 1, nbyte, aifffd[fd]);
/*
* convert bytes to samples
*/
return bytes_written / widthtobytes(audioparams[fd].sampwidth);
}
int AIFFread(AIFFfile fd, void* buf, unsigned nsamp)
{
int bytes_read, nbyte;
if (fd < 0 || fd >= MAXFILES || !busy[fd])
{
AIFFerrno = AIFF_BADFD;
return -1;
}
/*
* skip to next SSND block if necessary
*/
if (ssnd_remaining[fd] == 0)
read_ssnd_chunk(fd);
/*
* convert number samples to number bytes
*/
nbyte = nsamp * widthtobytes(audioparams[fd].sampwidth);
/*
* get samples
*/
/*
* FIXME: AIFFread should always attempt to fill the buffer
* even if has to read the next SSND block to
* do it (and the one after that, etc.)
*/
if (ssnd_remaining[fd] < nbyte)
bytes_read = fread(buf, 1, ssnd_remaining[fd], aifffd[fd]);
else
bytes_read = fread(buf, 1, nbyte, aifffd[fd]);
ssnd_remaining[fd] -= bytes_read;
/*
* convert bytes to samples
*/
return bytes_read / widthtobytes(audioparams[fd].sampwidth);
}
int AIFFgetlength(AIFFfile fd)
{
if (fd < 0 || fd >= MAXFILES || !busy[fd])
{
AIFFerrno = AIFF_BADFD;
return -1;
}
/*
* skip to next SSND block if necessary
*/
if (ssnd_remaining[fd] == 0)
read_ssnd_chunk(fd);
return ssnd_remaining[fd] / widthtobytes(audioparams[fd].sampwidth);
}
int AIFFgetchannels(AIFFfile fd)
{
if (fd < 0 || fd >= MAXFILES || !busy[fd])
{
AIFFerrno = AIFF_BADFD;
return -1;
}
return audioparams[fd].nchannels;
}
int AIFFgetwidth(AIFFfile fd)
{
if (fd < 0 || fd >= MAXFILES || !busy[fd])
{
AIFFerrno = AIFF_BADFD;
return -1;
}
return audioparams[fd].sampwidth;
}
int AIFFgetrate(AIFFfile fd)
{
if (fd < 0 || fd >= MAXFILES || !busy[fd])
{
AIFFerrno = AIFF_BADFD;
return -1;
}
return audioparams[fd].samprate;
}
int AIFFsetchannels(AIFFfile fd, int channels)
{
if (fd < 0 || fd >= MAXFILES || !busy[fd])
{
AIFFerrno = AIFF_BADFD;
return -1;
}
/*
* make sure file is write and we haven't written any sound yet
*/
if (ssnd_remaining[fd] != -1)
{
AIFFerrno = AIFF_PARAMSFIXED;
return -1;
}
if (channels == 0)
channels = DEFAULT_CHANNELS;
audioparams[fd].nchannels = channels;
return 0;
}
int AIFFsetwidth(AIFFfile fd, int width)
{
if (fd < 0 || fd >= MAXFILES || !busy[fd])
{
AIFFerrno = AIFF_BADFD;
return -1;
}
/*
* make sure file is write and we haven't written any sound yet
*/
if (ssnd_remaining[fd] != -1)
{
AIFFerrno = AIFF_PARAMSFIXED;
return -1;
}
if (width == 0)
width = DEFAULT_WIDTH;
audioparams[fd].sampwidth = width;
return 0;
}
int AIFFsetrate(AIFFfile fd, int rate)
{
if (fd < 0 || fd >= MAXFILES || !busy[fd])
{
AIFFerrno = AIFF_BADFD;
return -1;
}
/*
* make sure file is write and we haven't written any sound yet
*/
if (ssnd_remaining[fd] != -1)
{
AIFFerrno = AIFF_PARAMSFIXED;
return -1;
}
if (rate == 0)
rate = DEFAULT_RATE;
audioparams[fd].samprate = rate;
return 0;
}
static int widthtobytes(int width)
{
switch (width)
{
case 8: return 1;
case 16: return 2;
case 24: return 4; /* FIXME: is this 3 or 4 */
default: return -1;
}
}
int CONVERTchannelstoAL(int channels)
{
switch (channels)
{
case 1: return AL_MONO;
case 2: return AL_STEREO;
default: AIFFerrno = AIFF_BADCHANNELS; return -1;
}
}
int CONVERTALtochannels(int ALchannels)
{
switch (ALchannels)
{
case AL_MONO: return 1;
case AL_STEREO: return 2;
default: AIFFerrno = AIFF_BADCHANNELS; return -1;
}
}
int CONVERTwidthtoAL(int width)
{
switch (width)
{
case 8: return AL_SAMPLE_8;
case 16: return AL_SAMPLE_16;
case 24: return AL_SAMPLE_24;
default: AIFFerrno = AIFF_BADWIDTH; return -1;
}
}
int CONVERTALtowidth(int ALwidth)
{
switch (ALwidth)
{
case AL_SAMPLE_8: return 8;
case AL_SAMPLE_16: return 16;
case AL_SAMPLE_24: return 24;
default: AIFFerrno = AIFF_BADWIDTH; return -1;
}
}
int CONVERTratetoAL(int rate)
{
switch (rate)
{
case 48000: return AL_RATE_48000;
case 44100: return AL_RATE_44100;
case 32000: return AL_RATE_32000;
case 22050: return AL_RATE_22050;
case 16000: return AL_RATE_16000;
case 11025: return AL_RATE_11025;
case 8000: return AL_RATE_8000;
default: AIFFerrno = AIFF_BADRATE; return -1;
}
}
int CONVERTALtorate(int ALrate)
{
switch (ALrate)
{
case AL_RATE_48000: return 48000;
case AL_RATE_44100: return 44100;
case AL_RATE_32000: return 32000;
case AL_RATE_16000: return 16000;
case AL_RATE_8000: return 8000;
default: AIFFerrno = AIFF_BADRATE; return -1;
}
}
void AIFFerror(const char* s)
{
if (s && *s)
fprintf(stderr,"%s: ",s);
fprintf(stderr,"%s\n",AIFFerrstr[-AIFFerrno]);
AIFFerrno = 0;
}
char* AIFFstrerror(int err)
{
return AIFFerrstr[-err];
}
/*
* Copyright (C) 1988-1991 Apple Computer, Inc.
* All rights reserved.
*
* Machine-independent I/O routines for IEEE floating-point numbers.
*
* NaN's and infinities are converted to HUGE_VAL or HUGE, which
* happens to be infinity on IEEE machines. Unfortunately, it is
* impossible to preserve NaN's in a machine-independent way.
* Infinities are, however, preserved on IEEE machines.
*
* These routines have been tested on the following machines:
* Apple Macintosh, MPW 3.1 C compiler
* Apple Macintosh, THINK C compiler
* Silicon Graphics IRIS, MIPS compiler
* Cray X/MP and Y/MP
* Digital Equipment VAX
*
*
* Implemented by Malcolm Slaney and Ken Turkowski.
*
* Malcolm Slaney contributions during 1988-1990 include big- and little-
* endian file I/O, conversion to and from Motorola's extended 80-bit
* floating-point format, and conversions to and from IEEE single-
* precision floating-point format.
*
* In 1991, Ken Turkowski implemented the conversions to and from
* IEEE double-precision format, added more precision to the extended
* conversions, and accommodated conversions involving +/- infinity,
* NaN's, and denormalized numbers.
*/
#ifndef HUGE_VAL
#define HUGE_VAL HUGE
#endif
#define UnsignedToFloat(u) \
(((double)((long)(u - 2147483647L - 1))) + 2147483648.0)
#define FloatToUnsigned(f) \
((unsigned long)(((long)(f - 2147483648.0)) + 2147483647L + 1))
/****************************************************************
* Extended precision IEEE floating-point conversion routines.
****************************************************************/
static double ConvertFromIeeeExtended(char *bytes)
{
double f;
long expon;
unsigned long hiMant, loMant;
expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF);
hiMant = ((unsigned long)(bytes[2] & 0xFF) << 24)
| ((unsigned long)(bytes[3] & 0xFF) << 16)
| ((unsigned long)(bytes[4] & 0xFF) << 8)
| ((unsigned long)(bytes[5] & 0xFF));
loMant = ((unsigned long)(bytes[6] & 0xFF) << 24)
| ((unsigned long)(bytes[7] & 0xFF) << 16)
| ((unsigned long)(bytes[8] & 0xFF) << 8)
| ((unsigned long)(bytes[9] & 0xFF));
if (expon == 0 && hiMant == 0 && loMant == 0)
{
f = 0;
}
else
{
if (expon == 0x7FFF) /* Infinity or NaN */
{
f = HUGE_VAL;
}
else
{
expon -= 16383;
f = ldexp(UnsignedToFloat(hiMant), expon-=31);
f += ldexp(UnsignedToFloat(loMant), expon-=32);
}
}
if (bytes[0] & 0x80)
return -f;
else
return f;
}
static void ConvertToIeeeExtended(double num, char *bytes)
{
int sign;
int expon;
double fMant, fsMant;
unsigned long hiMant, loMant;
if (num < 0)
{
sign = 0x8000;
num *= -1;
}
else
{
sign = 0;
}
if (num == 0)
{
expon = 0; hiMant = 0; loMant = 0;
}
else
{
fMant = frexp(num, &expon);
if ((expon > 16384) || !(fMant < 1)) /* Infinity or NaN */
{
expon = sign|0x7FFF; /* infinity */
hiMant = 0;
loMant = 0;
}
else /* Finite */
{
expon += 16382;
if (expon < 0) /* denormalized */
{
fMant = ldexp(fMant, expon);
expon = 0;
}
expon |= sign;
fMant = ldexp(fMant, 32);
fsMant = floor(fMant);
hiMant = FloatToUnsigned(fsMant);
fMant = ldexp(fMant - fsMant, 32);
fsMant = floor(fMant);
loMant = FloatToUnsigned(fsMant);
}
}
bytes[0] = expon >> 8;
bytes[1] = expon;
bytes[2] = hiMant >> 24;
bytes[3] = hiMant >> 16;
bytes[4] = hiMant >> 8;
bytes[5] = hiMant;
bytes[6] = loMant >> 24;
bytes[7] = loMant >> 16;
bytes[8] = loMant >> 8;
bytes[9] = loMant;
}